package main.singleton;

/**
 * 懒汉式创建
 * @author: kejl
 * @create: 2020-07-13 23:18
 */
public class LazySingleton {
    //懒汉式嘛，等使用我的时候我再创建嘛，也就相当于延时加载
    private static  volatile  LazySingleton lazySingleton = null;

    private LazySingleton(){

    }

    // 方式1 synchronized 防止两个同时进来，synchronized 放在了头部啊，
    //每次都得进行同步啊，浪费性能 改进到方式2
    public LazySingleton getLazySingleton(){
        //两个突然进来怎么办
        synchronized (LazySingleton.class){
        if (lazySingleton ==null){
            lazySingleton =new LazySingleton();
        }

        }
        return lazySingleton;

    }

//方式二  判空大大减少了访问，但是 同步代码块之后是直接创建对象啊，
 //   被synchronized 阻塞的都要进行新生成一个对象啊 改进到方式3
    public LazySingleton getLazySingleton2(){
        //两个突然进来怎么办,我放到里面去，这先判空
        if(lazySingleton ==null){
            synchronized (LazySingleton.class){
                lazySingleton =new LazySingleton();
            }

        }
        return lazySingleton;

    }

    //方式三 lazySingleton之后进行了进一步的判断，打破了直接创建对象
    public LazySingleton getLazySingleton3(){
        //两个突然进来怎么办,我放到里面去，这先判空
        if(lazySingleton ==null){
            synchronized (LazySingleton.class){
                if(lazySingleton==null){
                    lazySingleton =new LazySingleton();
                }
            }

        }
        return lazySingleton;

    }

    //指令重排的问题
   // 因为对象的创建实际上是三条指令： 1、分配内存地址 2、内存地址初始化 3、返回内存地址句柄
  //  其中2、3之间可能发生指令冲排序，导致线程A正在创建对象先执行1、3两步，结果线程B进来判断句柄已经不为空，直接返回给上层方法，
  //  此时对象还没有正确初始化内存，导致上层方法发生严重错误
    public LazySingleton getLazySingleton4(){
        //两个突然进来怎么办,我放到里面去，这先判空
        if(lazySingleton ==null){
            synchronized (LazySingleton.class){
                if(lazySingleton==null){
                    lazySingleton =new LazySingleton();
                }
            }

        }
        return lazySingleton;

    }

}
